import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class ETimerScheduler implements Scheduler {
	double V = 0;
	int bandwidth = 0;
	int time_slot = 1;
	double power = 0;
	int slot_number = 100000;

	private int group_number = 5;
	private Group[] group_list;
	private BufferedReader signal_reader;

	private double energy_consumption = 0;
	private int totally_delay = 0;
	private double signal_strength = 0;

	private double metric_considering_app_char = 0;
	private int queue = 0;

	Recorder recorder;

	public int data = 0;
	private int send_data = 0;

	int queue_delay = 0;
	int queue_data = 0;

	double queue_performance_metric = 0;

	double energy_consumption_each[];

	double TailEnergy = 0;
	double TailPower = 0;

	double queue_overdue = 0;

	// 冲突产生的性能损失，数据量，能耗
	double overdue_perf_de = 0;
	double overdue_size = 0;
	double overdue_energy = 0;
	// 未冲突产生的性能损失，数据量，能耗
	double unod_perf_de = 0;
	double unod_size = 0;
	double unod_energy = 0;

	int last_send = -100;

	SignalGenerator sg=null;
	public ETimerScheduler(boolean Geometric) {

		sg=new SignalGenerator();
		
		group_list = new Group[group_number];

		recorder = new Recorder("-etimer");

		// 第一个参数为deadline,第二个参数为上层应用每个时隙发送数据量的平均值（poisson分布）

		/**
		 * 权重为1:1:1的情况
		 */
		if(Geometric==true)
		{
		group_list[0] = new Group(10, 60, 0, 1.0/ 5, recorder);
		group_list[1] = new Group(200, 60, 1, 1.0/ 5, recorder);
		group_list[2] = new Group(400, 60, 2, 1.0/ 5, recorder);
		group_list[3] = new Group(800, 60, 3, 1.0/ 5, recorder);
		group_list[4] = new Group(1600, 60, 4, 1.0/ 5, recorder);
		}
//			/**
//			 * 权重为1/omega并且归一化的情况
//			 */
		else
		{
			group_list[0] = new Group(10, 60, 0, 160.0/ 175, recorder);
			group_list[1] = new Group(200, 60, 1, 8.0/175 , recorder);
			group_list[2] = new Group(400, 60, 2, 4.0/175, recorder);
			group_list[3] = new Group(800, 60, 3, 2.0/ 175, recorder);
			group_list[4] = new Group(1600, 60, 4, 1.0/ 175, recorder);
		}
		// group_list[0] = new Group(10, 60, 0,1/10,recorder);
		// group_list[1] = new Group(200, 60, 1,1/200,recorder);
		// group_list[2] = new Group(5000, 60, 2,1/5000,recorder);

		// group_list[0] = new Group(100, 60, 0, 1 , recorder);
		// group_list[1] = new Group(200, 60, 1, 1 , recorder);
		// group_list[2] = new Group(400, 60, 2, 1 , recorder);
		// group_list[3] = new Group(800, 60, 3, 1 , recorder);
		// group_list[4] = new Group(1600, 60, 4, 1 , recorder);

		// group_list[0] = new Group(100, 60, 0, 1 / 100.0, recorder);
		// group_list[1] = new Group(200, 60, 1, 1 / 200.0, recorder);
		// group_list[2] = new Group(400, 60, 2, 1 / 400.0, recorder);
		// group_list[3] = new Group(800, 60, 3, 1 / 800.0, recorder);
		// group_list[4] = new Group(1600, 60, 4, 1 / 1600.0, recorder);

		energy_consumption_each = new double[group_number];

		try {
			signal_reader = new BufferedReader(new FileReader(new File("C:\\Users\\LZQ\\Desktop\\Lypunov_simulation_data\\signal_vector.csv")));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	@Override
	public void begin_scheduling(int slot_number) {
		// TODO Auto-generated method stub
		this.slot_number = slot_number;
		for (int t = 0; t < slot_number; t += time_slot) {
			// System.out.println("Time slot: " + t);
			// 读取信号强度，获得带宽，功率等参数
			signal_strength=sg.getSignal(t);
//			try {
//				signal_strength = Double.parseDouble(signal_reader.readLine());
//			} catch (NumberFormatException | IOException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
			V = getV();
			power = getPower();
			bandwidth = getBandwidth();

			TailPower = getTailPower(t);
			// System.err.println("slot: "+t+" V: "+V+" Signal Strength: "+signal_strength+" Power: "+power+" BandWidth: "+bandwidth+" .");
			// 更新队长
			queue = 0;
			for (Group gp : group_list) {
				gp.refreshState(t);
				queue += gp.queue_length_sum;
			}
			// 计算决策变量
			double D = queue * bandwidth - V * (power + TailPower);
			// recorder.recordD(D);
			// Recorder.recordlog(new StringBuffer("#############current queue length: "+queue+" byte. \n"));
			// recorder.recordlog(new StringBuffer("————current parameters: \n Q= " + queue + " \n u= " + bandwidth + " \n V= " +
			// V + " \n power= "
			// + power + " \n"));
			// recorder.recordlog(new StringBuffer("————D: Q*u-V*power=" + D + "—————\n"));
			if (D > 0) {
				// 发送决策
				int allocated_bandwidth = 0;
				send_data = 0;// 统计当前时隙内发送的数据量
				while (allocated_bandwidth < bandwidth) {
					// 每一次找出最早到达的那个数据单元进行发送
					int arr_time = Integer.MAX_VALUE;
					DataUnit earliest_du = null;
					Group earliest_gp = null;
					for (int i = 0; i < group_number; i++)
						for (DataUnit du : group_list[i].DataQueue) {
							if (du.arr_time <= arr_time) {
								earliest_du = du;
								earliest_gp = group_list[i];
								arr_time = du.arr_time;
							}
						}
					// arr_time未被修改，说明队列中没有数据单元_
					if (arr_time == Integer.MAX_VALUE)
						break;
					// System.err.println("slot: "+t+"energy addition: "+power+" J.");
					if (earliest_du.data.length > (bandwidth - allocated_bandwidth)) {
//						System.err.println("send data unit info: "+earliest_du.bound+" "+(t-earliest_du.arr_time));
						// 如果剩下的可分配的带宽不足以发送这个数据单元中的数据了
						// 实际发送的数据量为：bandwidth-allocated_bandwidth
						earliest_du.data = new byte[earliest_du.data.length - (bandwidth - allocated_bandwidth)];
						earliest_gp.queue_length[earliest_du.delay_level] -= (bandwidth - allocated_bandwidth);
						send_data += bandwidth - allocated_bandwidth;
						energy_consumption_each[earliest_gp.ID] += power * (bandwidth - allocated_bandwidth) / (1.0 * bandwidth);
						energy_consumption += power * (bandwidth - allocated_bandwidth) / (1.0 * bandwidth);
						// if ((t - earliest_du.arr_time) > earliest_du.bound) {
						// overdue+=(bandwidth - allocated_bandwidth) ;
						// //metric_considering_app_char += (bandwidth - allocated_bandwidth) * (t - earliest_du.arr_time) *
						// earliest_gp.max_penalty_factor;
						//
						// } else

						{
							metric_considering_app_char += earliest_gp.omega * (bandwidth - allocated_bandwidth)
												* Penalty.f((t - earliest_du.arr_time), earliest_du.bound);
							earliest_gp.totally_metric_considering_app_char += earliest_gp.omega * (bandwidth - allocated_bandwidth)
												* Penalty.f((t - earliest_du.arr_time), earliest_du.bound);
						}
						// 如果产生冲突
						if ((t - earliest_du.arr_time) > earliest_du.bound) {
							overdue_perf_de += earliest_gp.omega * (bandwidth - allocated_bandwidth)
												* Penalty.f((t - earliest_du.arr_time), earliest_du.bound);
							overdue_size += (bandwidth - allocated_bandwidth);
							overdue_energy += power * (bandwidth - allocated_bandwidth) / (1.0 * bandwidth);
							// System.out.println("冲突，"+overdue_perf_de+"    "+Penalty.f((t - earliest_du.arr_time),
							// earliest_du.bound)+"   "+ earliest_gp.omega+"   "+(bandwidth - allocated_bandwidth));
						} else {
							// 未产生冲突
							unod_perf_de += earliest_gp.omega * (bandwidth - allocated_bandwidth)
												* Penalty.f((t - earliest_du.arr_time), earliest_du.bound);

							unod_size += (bandwidth - allocated_bandwidth);
							unod_energy += power * (bandwidth - allocated_bandwidth) / (1.0 * bandwidth);

						}

						totally_delay += (bandwidth - allocated_bandwidth) * (t - earliest_du.arr_time);
						allocated_bandwidth = bandwidth;
						// recorder.recordlog(new StringBuffer("###########send " + (bandwidth - allocated_bandwidth) +
						// " bytes data.  cause delay: "
						// + ((bandwidth - allocated_bandwidth) * (t - earliest_du.arr_time)) + "\n"));
					} else {
//						System.err.println("send data unit info: "+earliest_du.bound+" "+(t-earliest_du.arr_time));
						// 如果剩下的带宽足以将整个数据单元的数据发送完毕
						earliest_gp.queue_length[earliest_du.delay_level] -= earliest_du.data.length;
						allocated_bandwidth += earliest_du.data.length;
						// recorder.recordlog(new StringBuffer("###########send " + (earliest_du.data.length) +
						// " bytes data.cause delay: "
						// + (earliest_du.data.length * (t - earliest_du.arr_time)) + "\n"));
						send_data += earliest_du.data.length;
						if ((t - earliest_du.arr_time) > earliest_du.bound) {
							// 如果产生冲突
							overdue_perf_de += earliest_gp.omega * earliest_du.data.length * Penalty.f((t - earliest_du.arr_time), earliest_du.bound);
							overdue_size += earliest_du.data.length;
							overdue_energy += power * (earliest_du.data.length) / (1.0 * bandwidth);
						} else {
							// 未产生冲突
							unod_perf_de += earliest_gp.omega * earliest_du.data.length * Penalty.f((t - earliest_du.arr_time), earliest_du.bound);

							unod_size += earliest_du.data.length;
							unod_energy += power * (earliest_du.data.length) / (1.0 * bandwidth);
						}
						energy_consumption_each[earliest_gp.ID] += power * (earliest_du.data.length) / (1.0 * bandwidth);
						energy_consumption += power * (earliest_du.data.length) / (1.0 * bandwidth);
						// if ((t - earliest_du.arr_time) > earliest_du.bound) {
						// // metric_considering_app_char += earliest_du.data.length * (t - earliest_du.arr_time) *
						// earliest_gp.max_penalty_factor;
						// overdue+= earliest_du.data.length ;
						// } else
						{
							metric_considering_app_char += earliest_gp.omega * earliest_du.data.length
												* Penalty.f((t - earliest_du.arr_time), earliest_du.bound);// (t -
																											// earliest_du.arr_time)
																											// *
																											// earliest_gp.omega;
							earliest_gp.totally_metric_considering_app_char += earliest_gp.omega * earliest_du.data.length
												* Penalty.f((t - earliest_du.arr_time), earliest_du.bound);
						}
						totally_delay += earliest_du.data.length * (t - earliest_du.arr_time);
						// 判断这个数据单元是否超过了deadline
						// if ((t - earliest_du.arr_time) > earliest_du.bound)
						// overdue++;
						// 数据单元发送完毕，从队列中移除
						earliest_gp.DataQueue.remove(earliest_du);

					}
				}
				if (allocated_bandwidth > 0) {
					last_send = t;
					TailEnergy += TailPower;
				}
				// if (allocated_bandwidth > 0)// 如果分配了带宽，那么说明有数据发送了，能耗增加
				// energy_consumption += power;
				data += send_data;
			} else {
				// 不发送，nothing to do
			}

			// 计算决策之后的队长
			queue = 0;
			for (Group gp : group_list) {
				for (int q : gp.queue_length)
					queue += q;
			}

			// 上面计算的是由发送数据包产生的时延和性能损失
			// 计算缓存在队列中的所有数据单元的时延、性能损失
			queue_delay = 0;
			queue_performance_metric = 0;
			queue_data = 0;
			queue_overdue = 0;
			for (int i = 0; i < group_number; i++) {
				for (DataUnit du : group_list[i].DataQueue) {
					queue_delay += (t - du.arr_time) * du.data.length;
					// if ((t - du.arr_time) > du.bound) {
					// //queue_performance_metric += du.delay * group_list[i].max_penalty_factor * du.data.length;
					// queue_overdue+=du.data.length;
					// } else
					{
						queue_performance_metric += group_list[i].omega * Penalty.f((t - du.arr_time), du.bound) * du.data.length;
						// group_list[i].totally_metric_considering_app_char+=Penalty.f2((t-du.arr_time), du.bound)*
						// du.data.length;
					}

					queue_data += du.data.length;
					// if ((t - du.arr_time) > du.bound)
					// queue_overdue++;
				}
			}
			// recorder.recordlog(new StringBuffer("there are " + queue_overdue +
			// " data unit in the queue pass its deadline.\n"));
			// recorder.recordQueueLength(queue);
			// recorder.recordEnergy(energy_consumption);
			// recorder.recordDelay(totally_delay + queue_delay);
			// recorder.recordMetric(metric_considering_app_char + queue_performance_metric);
			// recorder.recordDelayPerByte(1.0 * (totally_delay + queue_delay) / (data + queue_data));
			// recorder.recordSendData(data);
			// recorder.recordOverdue(queue_overdue + overdue);
		}
		int generated_data_number = 0;
		for (int i = 0; i < group_number; i++)
			generated_data_number += group_list[i].app.generated_data_size;

		System.out.print((int) (energy_consumption + TailEnergy) + ",");// 1)总能耗
		System.out.print((metric_considering_app_char + queue_performance_metric) + ",");// 2）总的性能损失量
		System.out.print((TailEnergy) + ",");// 3)尾能耗
		System.out.print((overdue_perf_de) + ",");// 4)冲突性能损失
		System.out.print((overdue_size) + ",");// 5)冲突数据量
		System.out.print((overdue_energy) + ",");// 6)冲突能耗
		System.out.print((unod_perf_de) + ",");// 7)未冲突性能损失
		System.out.print((unod_size) + ",");// 8)未冲突数据量
		System.out.print((unod_energy) + ",");// 9)未冲突能耗
		System.out.print((queue_performance_metric) + ",");// 10)队列中的性能损失
		System.out.print((generated_data_number) + ",");// 11)总产生的数据量
		System.out.print((data) + ",");// 12)发送的数据量
		System.out.print((queue_data) + "");// 13)缓存在队列中的数据量
		System.out.println();
		// System.out.println("," + (int) (metric_considering_app_char + queue_performance_metric));

		// System.out.println("Energy Consumption: " + (int) (energy_consumption+TailEnergy) + " J");
		// System.out.println("Tail Energy: " + (int) (TailEnergy) + " J");
		// System.out.println("Totally dealy: " + (int) (totally_delay + queue_delay) + " s*byte");
		// System.out.println("Totally metric considering app: " + (metric_considering_app_char + queue_performance_metric) +
		// " s*byte*(1/omega)");
		// System.out.println("Totally send data: " + (int) data + " byte");
		// System.out.println("Current Queue Length: " + queue);
		// System.out.println("Generated Data Size: " + generated_data_number);
		// System.out.println("Overdue number: " + (overdue + queue_overdue));
		// System.out.println("Delay per byte: "+(1.0*(totally_delay + queue_delay)/generated_data_number));
		//
		// double e_a = 0;
		// for (int i = 0; i < group_number; i++)
		// e_a += energy_consumption_each[i];
		// for (int i = 0; i < group_number; i++)
		// System.out.println(energy_consumption_each[i] / e_a);
		//
		// System.out.println("\nPerformance Degradation for each Group:");
		// double p_a = 0;
		// for (int i = 0; i < group_number; i++)
		// p_a += group_list[i].totally_metric_considering_app_char;
		// for (int i = 0; i < group_number; i++)
		// System.out.println(group_list[i].totally_metric_considering_app_char / p_a);
		//
		// System.out.println("V factor: " + V + "\n");
		// recorder.recordV_GP_BP(""+V+","+(metric_considering_app_char + queue_performance_metric)+","+(overdue +
		// queue_overdue)+","+energy_consumption);
		// recorder.flush();
	}

	public double getV() {
		return V;

	}



	public double getTailPower(int t) {
		if (last_send == -100)
			return 0;
		if ((t - last_send) > 7) {
			// 计算完整的一个tail
			return 732 * 3 + 388 * 4;
		} else if ((t - last_send) > 3) {
			return (t - last_send - 3 - 1) * 388 + 732 * 3;

		} else {
			return (t - last_send - 1) * 732;
		}
	}

	public int getBandwidth() {
		return (int) (2.667*signal_strength +293.73);
	}
	public double getPower() {
		return -25 * signal_strength - 1030.9;

	}
	
	
	public void setV(double v) {
		V = v;
	}
}
